#include "AclProcess.h"
#include <sys/time.h>
AclProcess::AclProcess()
{

}
AclProcess::~AclProcess()
{
    m_modelProcess = nullptr;
    aclError ret = aclrtSynchronizeStream(stream_);
    if (ret != ACL_ERROR_NONE) {
        cout << "some tasks in stream not done, ret = " << ret <<endl;
    }
    cout << "all tasks in stream done" << endl;
    ret = aclrtDestroyStream(stream_);
    if (ret != ACL_ERROR_NONE) {
        cout << "Destroy Stream faild, ret = " << ret <<endl;
    }
    cout << "Destroy Stream successfully" << endl;
    ret = aclrtDestroyContext(context_);
    if (ret != ACL_ERROR_NONE) {
        cout << "Destroy Context faild, ret = " << ret <<endl;
    }
    cout << "Destroy Context successfully" << endl;
    ret = aclFinalize();
    if (ret != ACL_ERROR_NONE) {
        cout << "Failed to deinit acl, ret = " << ret <<endl;
    }
    cout << "acl deinit successfully" << endl;
}

int AclProcess::Init(int deviceId, string modelPath)
{
    //Init
    aclError ret = aclInit(nullptr); // Initialize ACL
    if (ret != ACL_ERROR_NONE) {
        cout << "Failed to init acl, ret = " << ret <<endl;
        return ret;
    }
    cout << "acl init successfully" << endl;
    ret = aclrtCreateContext(&context_, deviceId);
    if (ret != ACL_ERROR_NONE) {
        cout << "Failed to set current context, ret = " << ret << endl;
        return ret;
    }
    cout << "Create context successfully" << endl;
    ret = aclrtSetCurrentContext(context_);
    if (ret != ACL_ERROR_NONE) {
        cout << "Failed to set current context, ret = " << ret << endl;
        return ret;
    }
    cout << "set context successfully" << endl;
    ret = aclrtCreateStream(&stream_);
    if (ret != ACL_ERROR_NONE) {
        cout << "Failed to create stream, ret = " << ret << endl;
        return ret;
    }
    cout << "Create stream successfully" << endl;
    //Load model
    if (m_modelProcess == nullptr) {
        m_modelProcess = std::make_shared<ModelProcess>(deviceId, "");
    }
    ret = m_modelProcess->Init(modelPath);

    if (ret != ACL_ERROR_NONE) {
        cout << "Failed to initialize m_modelProcess, ret = " << ret << endl;
        return ret;
    }
//    m_modelDesc = m_modelProcess->GetModelDesc();
//    //get model input description and malloc them
//    size_t inputSize = aclmdlGetNumInputs(m_modelDesc);
//    for (size_t i = 0; i < inputSize; i++) {
//        size_t bufferSize = aclmdlGetInputSizeByIndex(m_modelDesc, i);
//        void *inputBuffer = nullptr;
//        aclError ret = aclrtMalloc(&inputBuffer, bufferSize, ACL_MEM_MALLOC_NORMAL_ONLY);
//        if (ret != ACL_ERROR_NONE) {
//            cout << "Failed to malloc buffer, ret = " << ret << endl;
//            return ret;
//        }
//        inputBuffers.push_back(inputBuffer);
//        inputSizes.push_back(bufferSize);
//    }
//    //get model output description and malloc them
//    size_t outputSize = aclmdlGetNumOutputs(m_modelDesc);
//    for (size_t i = 0; i < outputSize; i++) {
//        size_t bufferSize = aclmdlGetOutputSizeByIndex(m_modelDesc, i);
//        void *outputBuffer = nullptr;
//        aclError ret = aclrtMalloc(&outputBuffer, bufferSize, ACL_MEM_MALLOC_NORMAL_ONLY);
//        if (ret != ACL_ERROR_NONE) {
//            cout << "Failed to malloc buffer, ret = " << ret << endl;
//            return ret;
//        }
//        outputBuffers.push_back(outputBuffer);
//        outputSizes.push_back(bufferSize);
//    }
    cout << "finish init AclProcess" << endl;
    return ACL_ERROR_NONE;
}

int AclProcess::Process(Mat& img)
{
    struct timeval start;
    struct timeval end;
    gettimeofday(&start,NULL);
    aclError ret = ACL_ERROR_NONE;

    int32_t bbox_num = 1;
    int32_t image_info[2] = {img.cols, img.rows};
    int32_t bbox_data[4] = {100, 100, 200, 200};
    int32_t bbox_color[3] = {0, 255, 0};
    int32_t bbox_thickness = 2;
    //image data
    void *imageBuffer = nullptr;
    int32_t imageSize = img.cols * img.rows * img.channels();
    ret = aclrtMalloc(&imageBuffer, imageSize, ACL_MEM_MALLOC_NORMAL_ONLY);
    if (ret != ACL_ERROR_NONE) {
        cout << "Failed to malloc buffer, ret = " << ret << endl;
        return ret;
    }
    inputBuffers.push_back(imageBuffer);
    inputSizes.push_back(imageSize);
    //image info
    void* ptr_image_info = nullptr;
    ret = aclrtMalloc(&ptr_image_info, 2 * sizeof(int32_t), ACL_MEM_MALLOC_NORMAL_ONLY);
    if (ret != ACL_ERROR_NONE) {
        cout << "Failed to malloc buffer, ret = " << ret << endl;
        return ret;
    }
    inputBuffers.push_back(ptr_image_info);
    inputSizes.push_back(2 * sizeof(int32_t));
    //bbox data
    void* ptr_bbox_data = nullptr;
    ret = aclrtMalloc(&ptr_bbox_data, bbox_num * 4 * sizeof(int32_t), ACL_MEM_MALLOC_NORMAL_ONLY);
    if (ret != ACL_ERROR_NONE) {
        cout << "Failed to malloc buffer, ret = " << ret << endl;
        return ret;
    }
    inputBuffers.push_back(ptr_bbox_data);
    inputSizes.push_back(bbox_num * 4 * sizeof(int32_t));
    //bbox num
    void* ptr_bbox_num = nullptr;
    ret = aclrtMalloc(&ptr_bbox_num, 1 * sizeof(int32_t), ACL_MEM_MALLOC_NORMAL_ONLY);
    if (ret != ACL_ERROR_NONE) {
        cout << "Failed to malloc buffer, ret = " << ret << endl;
        return ret;
    }
    inputBuffers.push_back(ptr_bbox_num);
    inputSizes.push_back(1 * sizeof(int32_t));
    //bbox color
    void* ptr_bbox_color = nullptr;
    ret = aclrtMalloc(&ptr_bbox_color, 3 * sizeof(int32_t), ACL_MEM_MALLOC_NORMAL_ONLY);
    if (ret != ACL_ERROR_NONE) {
        cout << "Failed to malloc buffer, ret = " << ret << endl;
        return ret;
    }
    inputBuffers.push_back(ptr_bbox_color);
    inputSizes.push_back(3 * sizeof(int32_t));
    //bbox thickness
    void* ptr_bbox_thickness = nullptr;
    ret = aclrtMalloc(&ptr_bbox_thickness, 1 * sizeof(int32_t), ACL_MEM_MALLOC_NORMAL_ONLY);
    if (ret != ACL_ERROR_NONE) {
        cout << "Failed to malloc buffer, ret = " << ret << endl;
        return ret;
    }
    inputBuffers.push_back(ptr_bbox_thickness);
    inputSizes.push_back(1 * sizeof(int32_t));

    aclrtMemcpy(inputBuffers[0], inputSizes[0], img.data, inputSizes[0], ACL_MEMCPY_HOST_TO_DEVICE);
    aclrtMemcpy(inputBuffers[1], inputSizes[1], image_info, inputSizes[1], ACL_MEMCPY_HOST_TO_DEVICE);
    aclrtMemcpy(inputBuffers[2], inputSizes[2], bbox_data, inputSizes[2], ACL_MEMCPY_HOST_TO_DEVICE);
    aclrtMemcpy(inputBuffers[3], inputSizes[3], &bbox_num, inputSizes[3], ACL_MEMCPY_HOST_TO_DEVICE);
    aclrtMemcpy(inputBuffers[4], inputSizes[4], bbox_color, inputSizes[4], ACL_MEMCPY_HOST_TO_DEVICE);
    aclrtMemcpy(inputBuffers[5], inputSizes[5], &bbox_thickness, inputSizes[5], ACL_MEMCPY_HOST_TO_DEVICE);

    void* ptr_output = nullptr;
    ret = aclrtMalloc(&ptr_output, 1 * sizeof(int32_t), ACL_MEM_MALLOC_NORMAL_ONLY);
    if (ret != ACL_ERROR_NONE) {
        cout << "Failed to malloc buffer, ret = " << ret << endl;
        return ret;
    }
    outputBuffers.push_back(ptr_output);
    outputSizes.push_back(1 * sizeof(int32_t));

    gettimeofday(&end,NULL);
    cout<<"copy data to device time : "<<(end.tv_sec-start.tv_sec)*1000+(end.tv_usec-start.tv_usec) / 1000.0 <<"ms"<<endl;
    gettimeofday(&start,NULL);

    //forward
    ret = m_modelProcess->ModelInference(inputBuffers, inputSizes, outputBuffers, outputSizes);
    if (ret != ACL_ERROR_NONE) {
        cout<<"model run faild.ret = "<< ret <<endl;
        return ret;
    }

    gettimeofday(&end,NULL);
    cout<<"model infer time : "<<(end.tv_sec-start.tv_sec)*1000+(end.tv_usec-start.tv_usec) / 1000.0 <<"ms"<<endl;
    gettimeofday(&start,NULL);

    aclrtMemcpy(img.data, inputSizes[0], inputBuffers[0], inputSizes[0], ACL_MEMCPY_DEVICE_TO_HOST);

    gettimeofday(&end,NULL);
    cout<<"copy data to host time : "<<(end.tv_sec-start.tv_sec)*1000+(end.tv_usec-start.tv_usec) / 1000.0 <<"ms"<<endl;
    imwrite("output.jpg", img);

    return ACL_ERROR_NONE;
}
